//
// Created by fazhehy on 2024/4/14.
//

#include "bldc_pwm.h"

void bldc_pwm_init()
{
    /******************************����ֲ�����******************************/
    cy_stc_gpio_pin_config_t            pwm_pin_config;                         // ����PWM�������ö���
    cy_stc_tcpwm_pwm_config_t           tcpwm_pwm_config;                       // ����PWM��ʱ�����ö���
    /******************************����ֲ�����******************************/

    /******************************����PWM����******************************/
    memset(&pwm_pin_config, 0, sizeof(pwm_pin_config));                         // ���PWM���Ŷ������

    pwm_pin_config.driveMode                     = CY_GPIO_DM_STRONG;           // ����PWM�������ģʽΪǿ����ģʽ
    // ��ʼ��A����������
    pwm_pin_config.hsiom                         = P9_0_TCPWM0_LINE24;
    Cy_GPIO_Pin_Init(get_port(A_PHASE_PIN_H), (A_PHASE_PIN_H % 8), &pwm_pin_config);
    // ��ʼ��A����������
    pwm_pin_config.hsiom                         = P9_1_TCPWM0_LINE_COMPL24;
    Cy_GPIO_Pin_Init(get_port(A_PHASE_PIN_L), (A_PHASE_PIN_L % 8), &pwm_pin_config);
    // ��ʼ��B����������
    pwm_pin_config.hsiom                         = P5_0_TCPWM0_LINE9;
    Cy_GPIO_Pin_Init(get_port(B_PHASE_PIN_H), (B_PHASE_PIN_H % 8), &pwm_pin_config);
    // ��ʼ��B����������
    pwm_pin_config.hsiom                         = P5_1_TCPWM0_LINE_COMPL9;
    Cy_GPIO_Pin_Init(get_port(B_PHASE_PIN_L), (B_PHASE_PIN_L % 8), &pwm_pin_config);
    // ��ʼ��C����������
    pwm_pin_config.hsiom                         = P5_2_TCPWM0_LINE11;
    Cy_GPIO_Pin_Init(get_port(C_PHASE_PIN_H), (C_PHASE_PIN_H % 8), &pwm_pin_config);
    // ��ʼ��C����������
    pwm_pin_config.hsiom                         = P5_3_TCPWM0_LINE_COMPL11;
    Cy_GPIO_Pin_Init(get_port(C_PHASE_PIN_L), (C_PHASE_PIN_L % 8), &pwm_pin_config);
    /******************************����PWM����******************************/


    /****************************����PWM��ʱ��ʱ��***************************/
    // ��ʼ��A��ʱ��  ��ʱ��ͨ��24   ʹ��16λ��Ƶ����ͨ��1 ����Ƶֱ�����80Mhzʱ�ӵ���ʱ��
    Cy_SysClk_PeriphAssignDivider(PCLK_TCPWM0_CLOCKS24, CY_SYSCLK_DIV_16_BIT, 2);
    Cy_SysClk_PeriphSetDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS24), CY_SYSCLK_DIV_16_BIT, 2, 0);
    Cy_SysClk_PeriphEnableDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS24), CY_SYSCLK_DIV_16_BIT, 2);
    // ��ʼ��B��ʱ��  ��ʱ��ͨ��9    ʹ��16λ��Ƶ����ͨ��1 ����Ƶֱ�����80Mhzʱ�ӵ���ʱ��
    Cy_SysClk_PeriphAssignDivider(PCLK_TCPWM0_CLOCKS9, CY_SYSCLK_DIV_16_BIT, 2);
    Cy_SysClk_PeriphSetDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS9), CY_SYSCLK_DIV_16_BIT, 2, 0);
    Cy_SysClk_PeriphEnableDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS9), CY_SYSCLK_DIV_16_BIT, 2);
    // ��ʼ��C��ʱ��  ��ʱ��ͨ��11   ʹ��16λ��Ƶ����ͨ��1 ����Ƶֱ�����80Mhzʱ�ӵ���ʱ��
    Cy_SysClk_PeriphAssignDivider(PCLK_TCPWM0_CLOCKS11, CY_SYSCLK_DIV_16_BIT, 2);
    Cy_SysClk_PeriphSetDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS11), CY_SYSCLK_DIV_16_BIT, 2, 0);
    Cy_SysClk_PeriphEnableDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS11), CY_SYSCLK_DIV_16_BIT, 2);

    Cy_SysClk_PeriphAssignDivider(PCLK_TCPWM0_CLOCKS12, CY_SYSCLK_DIV_16_BIT, 2);
    Cy_SysClk_PeriphSetDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS12), CY_SYSCLK_DIV_16_BIT, 2, 0);
    Cy_SysClk_PeriphEnableDivider(Cy_SysClk_GetClockGroup(PCLK_TCPWM0_CLOCKS12), CY_SYSCLK_DIV_16_BIT, 2);
    /****************************����PWM��ʱ��ʱ��***************************/


    /*****************************����PWM��ʱ��******************************/
    memset(&tcpwm_pwm_config, 0, sizeof(tcpwm_pwm_config));                     // �����ʱ�����ò���

    tcpwm_pwm_config.pwmMode            = CY_TCPWM_PWM_MODE_DEADTIME      ;     // ��ǰģʽΪPWM����ģʽ ���Ի������������������ʱ��
    tcpwm_pwm_config.countDirection     = CY_TCPWM_COUNTER_COUNT_UP       ;     // ���������ϼ���
    tcpwm_pwm_config.cc0MatchMode       = CY_TCPWM_PWM_TR_CTRL2_SET       ;     // ���ȽϼĴ���0�������ƥ��ʱ �����������
    tcpwm_pwm_config.cc1MatchMode       = CY_TCPWM_PWM_TR_CTRL2_CLEAR     ;     // ���ȽϼĴ���1�������ƥ��ʱ �����������
    tcpwm_pwm_config.overflowMode       = CY_TCPWM_PWM_TR_CTRL2_CLEAR     ;     // ������������ʱ �����������
    tcpwm_pwm_config.underflowMode      = CY_TCPWM_PWM_TR_CTRL2_NO_CHANGE ;     // ������������ʱ ��������仯(���ϼ���ģʽ���ᴥ����������)
    tcpwm_pwm_config.deadTime           = 20                              ;     // ����ʱ��Ϊ10��ʱ������ 80mhzʱ�ӵ�10������Ϊ125ns
    tcpwm_pwm_config.deadTimeComp       = 20                              ;     // ����ͨ������ʱ��ҲΪ10��ʱ������
    tcpwm_pwm_config.runMode            = CY_TCPWM_PWM_CONTINUOUS         ;     // �������� �������PWM�ź�
    tcpwm_pwm_config.clockPrescaler     = CY_TCPWM_PRESCALER_DIVBY_1      ;     // ʱ��1��Ƶ 80Mhzʱ��ֱ�������ڶ�ʱ�� ��λʱ������Ϊ12.5ns
    tcpwm_pwm_config.period             = (PWM_PRIOD_LOAD - 1)            ;     // ��ʱ������Ϊ4000 80Mhz�������ڵõ�Ƶ��Ϊ20Khz
    tcpwm_pwm_config.compare0           = 0                               ;     // �ȽϼĴ���0���
    tcpwm_pwm_config.compare1           = 0                               ;     // �ȽϼĴ���1���
    tcpwm_pwm_config.enableCompare0Swap = true                            ;     // �Ƚ���0����ʹ�� �˴�ΪԤװ�ع���ʵ�� �û��ıȽ�����д�뻺���� ����¼��������������������Լ�ʵ�ʱȽϼĴ�����ֵ
    tcpwm_pwm_config.enableCompare1Swap = true                            ;     // �Ƚ���1����ʹ��
    tcpwm_pwm_config.killMode           = CY_TCPWM_PWM_STOP_ON_KILL       ;     // �رն�ʱ��ʱֹͣ����
    tcpwm_pwm_config.countInputMode     = CY_TCPWM_INPUT_LEVEL            ;     // �����¼�Ϊ����
    tcpwm_pwm_config.countInput         = 1uL                             ;     // �����¼�����ߵ�ƽ

    // ��ʼ��A��PWMͨ��   �����������ͨ�����ò���һ�� ��ֱ��ʹ��ͬһ�����ö��������ͨ����ɲ�������
    Cy_Tcpwm_Pwm_Init(TCPWM0_GRP0_CNT24, &tcpwm_pwm_config);
    Cy_Tcpwm_Pwm_Enable(TCPWM0_GRP0_CNT24);
    Cy_Tcpwm_Counter_SetTC_IntrMask(TCPWM0_GRP0_CNT24);
    Cy_Tcpwm_TriggerStart(TCPWM0_GRP0_CNT24);

    // ��ʼ��B��PWMͨ��   �����������ͨ�����ò���һ�� ��ֱ��ʹ��ͬһ�����ö��������ͨ����ɲ�������
    Cy_Tcpwm_Pwm_Init(TCPWM0_GRP0_CNT9, &tcpwm_pwm_config);
    Cy_Tcpwm_Pwm_Enable(TCPWM0_GRP0_CNT9);
    Cy_Tcpwm_TriggerStart(TCPWM0_GRP0_CNT9);

    // ��ʼ��C��PWMͨ��   �����������ͨ�����ò���һ�� ��ֱ��ʹ��ͬһ�����ö��������ͨ����ɲ�������
    Cy_Tcpwm_Pwm_Init(TCPWM0_GRP0_CNT11, &tcpwm_pwm_config);
    Cy_Tcpwm_Pwm_Enable(TCPWM0_GRP0_CNT11);
    Cy_Tcpwm_TriggerStart(TCPWM0_GRP0_CNT11);
    /*****************************����PWM��ʱ��******************************/


    /***************************��ʱ������ͬ������****************************/
    // ��������ͨ�����Ƕ����Ķ�ʱ�� ��ôcounter�Ĵ����ļ���ֵҲ�Ǹ��Լ���
    // ���counter��ͬ���Ļ� �������·PWM���ξ��޷�����
    // �˴�Ϊ��򵥵�αͬ��������������ת�������·counter�Ĵ�������
    // ���Ȼ�ȡcounter�Ĵ����ĵ�ַ
    uint32 pwm_ch24_count_address = 0x40580C00 + 0x00000008;                    // ͨ��24��ַ + COUNTER�Ĵ���ƫ����
    uint32 pwm_ch09_count_address = 0x40580480 + 0x00000008;                    // ͨ��09��ַ + COUNTER�Ĵ���ƫ����
    uint32 pwm_ch11_count_address = 0x40580580 + 0x00000008;                    // ͨ��11��ַ + COUNTER�Ĵ���ƫ����
    // ͨ��ָ����ʼĴ�����ַ
    volatile uint32_t *pwm_ch24_count_pointer = (volatile uint32_t *)pwm_ch24_count_address;
    volatile uint32_t *pwm_ch09_count_pointer = (volatile uint32_t *)pwm_ch09_count_address;
    volatile uint32_t *pwm_ch11_count_pointer = (volatile uint32_t *)pwm_ch11_count_address;
    // ֱ�Ӷ�ָ��ָ��ļĴ�����ֵ0
    *pwm_ch24_count_pointer     = 0;
    *pwm_ch09_count_pointer     = 0;
    *pwm_ch11_count_pointer     = 0;
    /***************************��ʱ������ͬ������****************************/
}

void bldc_duty_set(uint16_t a_duty, uint16_t b_duty, uint16_t c_duty)
{
    // ��������ͨ�����Ƕ����Ķ�ʱ�� ��ôcounter�Ĵ����ļ���ֵҲ�Ǹ��Լ���
    // ���counter��ͬ���Ļ� �������·PWM���ξ��޷�����
    // �˴�Ϊ��򵥵�αͬ��������������ת�������·counter�Ĵ�������
    // ���Ȼ�ȡcounter�Ĵ����ĵ�ַ
    uint32 pwm_ch24_count_address = 0x40580C00 + 0x00000008;                    // ͨ��24��ַ + COUNTER�Ĵ���ƫ����
    uint32 pwm_ch09_count_address = 0x40580480 + 0x00000008;                    // ͨ��09��ַ + COUNTER�Ĵ���ƫ����
    uint32 pwm_ch11_count_address = 0x40580580 + 0x00000008;                    // ͨ��11��ַ + COUNTER�Ĵ���ƫ����
    // ͨ��ָ����ʼĴ�����ַ
    volatile uint32_t *pwm_ch24_count_pointer = (volatile uint32_t *)pwm_ch24_count_address;
    volatile uint32_t *pwm_ch09_count_pointer = (volatile uint32_t *)pwm_ch09_count_address;
    volatile uint32_t *pwm_ch11_count_pointer = (volatile uint32_t *)pwm_ch11_count_address;
    // ���Ķ����PWMʵ�ַ�ʽ��ͨ�������Ƚ����Ƚ�˫�ߵ�ֵ counter�Ĵ��������ϼ���
    // ��counter����ֵ���ڱȽ���1��ֵʱ�������������
    // ��counter����ֵ���ڱȽ���2��ֵʱ�������������
    TCPWM0_GRP0_CNT24->unCC0.u32Register = (PWM_PRIOD_LOAD - a_duty) / 2;  // ����A��ͨ���Ƚ���1��ֵ
    TCPWM0_GRP0_CNT24->unCC1.u32Register = (PWM_PRIOD_LOAD + a_duty) / 2;  // ����A��ͨ���Ƚ���2��ֵ
    TCPWM0_GRP0_CNT9->unCC0.u32Register  = (PWM_PRIOD_LOAD - b_duty) / 2;  // ����B��ͨ���Ƚ���1��ֵ
    TCPWM0_GRP0_CNT9->unCC1.u32Register  = (PWM_PRIOD_LOAD + b_duty) / 2;  // ����B��ͨ���Ƚ���2��ֵ
    TCPWM0_GRP0_CNT11->unCC0.u32Register = (PWM_PRIOD_LOAD - c_duty) / 2;  // ����C��ͨ���Ƚ���1��ֵ
    TCPWM0_GRP0_CNT11->unCC1.u32Register = (PWM_PRIOD_LOAD + c_duty) / 2;  // ����C��ͨ���Ƚ���2��ֵ
    // ֱ�Ӷ�ָ��ָ��ļĴ�����ֵ0
    *pwm_ch24_count_pointer     = 0;
    *pwm_ch09_count_pointer     = 0;
    *pwm_ch11_count_pointer     = 0;
}

void bldc_channel_set(uint8_t a_channel, uint8_t b_channel, uint8_t c_channel)
{
    if(a_channel)                                                               // ��A��ͨ��ʹ������ͨ��
    {
        TCPWM0_GRP0_CNT24->unCTRL.u32Register       |= 0x80000000;              // ʹ�ܶ�ʱ��
        TCPWM0_GRP0_CNT24->unTR_CMD.u32Register      = 0x00000004;              // ��������
    }
    else                                                                        // ����ر�A��ͨ��ʹ��
    {
        TCPWM0_GRP0_CNT24->unCTRL.u32Register       &= 0x7FFFFFFF;              // �ر�A��ͨ��ʹ��
    }
    if(b_channel)                                                               // ��B��ͨ��ʹ������ͨ��
    {
        TCPWM0_GRP0_CNT9->unCTRL.u32Register        |= 0x80000000;              // ʹ�ܶ�ʱ��
        TCPWM0_GRP0_CNT9->unTR_CMD.u32Register       = 0x00000004;              // ��������
    }
    else                                                                        // ����ر�B��ͨ��ʹ��
    {
        TCPWM0_GRP0_CNT9->unCTRL.u32Register        &= 0x7FFFFFFF;              // �ر�B��ͨ��ʹ��
    }
    if(c_channel)                                                               // ��C��ͨ��ʹ������ͨ��
    {
        TCPWM0_GRP0_CNT11->unCTRL.u32Register       |= 0x80000000;              // ʹ�ܶ�ʱ��
        TCPWM0_GRP0_CNT11->unTR_CMD.u32Register      = 0x00000004;              // ��������
    }
    else                                                                        // ����ر�C��ͨ��ʹ��
    {
        TCPWM0_GRP0_CNT11->unCTRL.u32Register       &= 0x7FFFFFFF;              // �ر�C��ͨ��ʹ��
    }
}

void bldc_pwm_output(uint8_t hallValue, int16_t duty)
{
    uint16_t bldc_duty_temp;
    if (duty < 0)
        bldc_duty_temp = -duty;
    else
        bldc_duty_temp = duty;

    if (bldc_duty_temp >= max_duty)
        bldc_duty_temp = max_duty-1;

    switch (hallValue) {
        case 2:
            bldc_duty_set(bldc_duty_temp, 0, 0);
            bldc_channel_set(1, 1, 0);
            break;
        case 6:
            bldc_duty_set(bldc_duty_temp, 0, 0);
            bldc_channel_set(1, 0, 1);
            break;
        case 4:
            bldc_duty_set(0, bldc_duty_temp, 0);
            bldc_channel_set(0, 1, 1);
            break;
        case 5:
            bldc_duty_set(0, bldc_duty_temp, 0);
            bldc_channel_set(1, 1, 0);
            break;
        case 1:
            bldc_duty_set(0, 0, bldc_duty_temp);
            bldc_channel_set(1, 0, 1);
            break;
        case 3:
            bldc_duty_set(0, 0, bldc_duty_temp);
            bldc_channel_set(0, 1, 1);
            break;
        default:
            bldc_duty_set(0, 0, 0);
            bldc_channel_set(0, 0, 0);
            break;
    }
}
